#include "nativeaudioplayer.h"


NativeAudioPlayer* NativeAudioPlayer::m_pInstanse = 0;

NativeAudioPlayer::NativeAudioPlayer(QObject *parent) :
    QObject(parent)
{

    for (int i = 0; i < SAWTOOTH_FRAMES; ++i)
    {
        //sawtoothBuffer[i] = 32768 - ((i % 100) * 660);
        sawtoothBuffer[i] = 20000*sin(2*PI*440*i/8000.0);
    }

    for (int i = 0; i < FRAMES_600; ++i)
    {
        buffer600[i] = 20000*sin(2*PI*600*i/8000.0);
    }

    for (int i = 0; i < FRAMES_1200; ++i)
    {
        buffer1200[i] = 20000*sin(2*PI*1200*i/8000.0);
    }

    for (int i = 0; i < FRAMES_SILENCE; ++i)
    {
        bufferSilence[i] = 0;
    }

    playbackIndex = -1;

    m_pInstanse = this;

    playingSingle = 0;

    createEngine();
    createBufferQueueAudioPlayer();
}

void NativeAudioPlayer::createEngine()
{
    SLresult result;

    // create engine
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // realize the engine
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the engine interface, which is needed in order to create other objects
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    assert(SL_RESULT_SUCCESS == result);

    // create output mix, with environmental reverb specified as a non-required interface
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
    assert(SL_RESULT_SUCCESS == result);

    // realize the output mix
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);
}

void NativeAudioPlayer::createBufferQueueAudioPlayer()
{
    SLresult result;

    // configure audio source
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1,
                                   SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
                                   SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
    SLDataSource audioSrc = {&loc_bufq, &format_pcm};

    // configure audio sink
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};

    // create audio player
    const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND};
    const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
                                                2, ids, req);
    assert(SL_RESULT_SUCCESS == result);

    // realize the player
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the play interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    assert(SL_RESULT_SUCCESS == result);

    // get the buffer queue interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                             &bqPlayerBufferQueue);
    assert(SL_RESULT_SUCCESS == result);


    // register callback on the buffer queue
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallbackStatic, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // get the effect send interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
                                             &bqPlayerEffectSend);
    assert(SL_RESULT_SUCCESS == result);

    // set the player's state to playing
    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
    assert(SL_RESULT_SUCCESS == result);
}

void NativeAudioPlayer::play()
{
    SLresult result;
    nextBuffer = (short*) buffer600;
    nextSize = sizeof(buffer600);
    playbackIndex = 0;
    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
}

void NativeAudioPlayer::bqPlayerCallbackStatic(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    m_pInstanse->bqPlayerCallback(bq, context);
}

void NativeAudioPlayer::bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{

    if (playingSingle)
        return;

    SLresult result;

    if (playbackIndex == 0)
    {
        nextBuffer = (short*) bufferSilence;
        nextSize = sizeof(bufferSilence);

        //nextBuffer = (short*) buffer1200;
        //nextSize = sizeof(buffer1200);
    }
    else if (playbackIndex == 1)
    {
        nextBuffer = (short*) buffer600;
        nextSize = sizeof(buffer600);
    }
    playbackIndex = !playbackIndex;

   // QString out = QString::number(QDateTime::currentMSecsSinceEpoch());
   // SLmillisecond foo;
    //(*bqPlayerPlay)->GetPosition(bqPlayerPlay,&foo);
    //tt = QDateTime::currentMSecsSinceEpoch();

    //out.append(" ");
    //out.append(QString::number(foo));
    //__android_log_write(ANDROID_LOG_INFO, "SBS2", out.toStdString().c_str());



    //emit event(QString::number(playbackIndex)+"_"+QString::number(tt)+"_"+QString::number(foo));

    //emit event(out);


    //non-blocking call
    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);

    /*
    struct timespec time1;
    clock_gettime(CLOCK_MONOTONIC, &time1);
    long t = time1.tv_sec*1000.0 + time1.tv_nsec/1000000.0;
    char buffer [50];
    sprintf (buffer, "end %d", t);
    __android_log_write(ANDROID_LOG_INFO, "SBS2", buffer);
*/


}

void NativeAudioPlayer::playSingle()
{
    playingSingle = 1;
    nextBuffer = (short*) buffer600;
    nextSize = sizeof(buffer600);

    /*
     QString out = QString::number(QDateTime::currentMSecsSinceEpoch());
     out.append(" ");
     out.append(QString::number(Sbs2Callback::getCurrentPacket()));

     SLmillisecond foo;
     (*bqPlayerPlay)->GetPosition(bqPlayerPlay,&foo);
     tt = QDateTime::currentMSecsSinceEpoch();

     out.append(" ");
     out.append(QString::number(foo));
*/

    (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);



//    out.append(" ");
  //  out.append(QString::number(Sbs2Callback::getCurrentPacket()));
   // __android_log_write(ANDROID_LOG_INFO, "SBS2", out.toStdString().c_str());


}

int NativeAudioPlayer::playbackPosition()
{
    SLmillisecond foo;
    (*bqPlayerPlay)->GetPosition(bqPlayerPlay,&foo);
    return foo;
}
